<template>
  <div>
    <div class="editor-controls">
      <button @click="toggleMode" class="mode-toggle">
        {{ isMarkdownMode ? '切换到富文本模式' : '切换到 Markdown 模式' }}
      </button>
      <button @click="getMarkdown" class="get-markdown">
        获取 Markdown
      </button>
    </div>
    <div class="editor-wrapper">
      <textarea
        v-if="isMarkdownMode"
        v-model="markdownContent"
        class="markdown-editor"
        @input="updateFromMarkdown"
      ></textarea>
      <editor-content v-else :editor="editor" />
    </div>
    <div v-if="markdownOutput" class="markdown-output">
      <h4>Markdown 输出：</h4>
      <pre>{{ markdownOutput }}</pre>
    </div>
  </div>
</template>

<script>
import Highlight from "@tiptap/extension-highlight";
import Typography from "@tiptap/extension-typography";
import StarterKit from "@tiptap/starter-kit";
import Table from "@tiptap/extension-table";
import TableRow from "@tiptap/extension-table-row";
import TableHeader from "@tiptap/extension-table-header";
import TableCell from "@tiptap/extension-table-cell";
import TaskList from "@tiptap/extension-task-list";
import TaskItem from "@tiptap/extension-task-item";
import Link from "@tiptap/extension-link";
import Markdown from "@tiptap/extension-markdown";
import { Editor, EditorContent } from "@tiptap/vue-3";

export default {
  components: {
    EditorContent,
  },

  data() {
    return {
      editor: null,
      isMarkdownMode: false,
      markdownContent: '',
      markdownOutput: '',
    };
  },

  mounted() {
    this.editor = new Editor({
      extensions: [
        StarterKit,
        Highlight,
        Typography,
        Markdown.configure({
          html: true,
          tightLists: true,
          tightListClass: 'tight',
          bulletListMarker: '-',
          linkify: false,
          breaks: false,
          transformPastedText: true,
          transformCopiedText: true,
        }),
        Link.configure({
          openOnClick: false,
        }),
        Table.configure({
          resizable: true,
        }),
        TableRow,
        TableHeader,
        TableCell,
        TaskList,
        TaskItem.configure({
          nested: true,
        }),
      ],
      content: `# Tiptap Markdown 编辑器演示

这是一个基于 Tiptap 的 Markdown 编辑器演示，现在使用了官方的 **@tiptap/extension-markdown** 扩展。

Markdown 快捷输入让格式化文本变得简单。尝试在新行开始输入 \`#\` 后跟空格来创建标题。

支持的快捷键包括：\`>\` 用于引用，\`*\`、\`-\` 或 \`+\` 用于无序列表，\`\\\`代码\\\`\` 用于行内代码，\`~~删除线~~\`，\`==高亮==\`。

## 任务列表

输入 \`[ ]\` 或 \`[x]\` 后跟空格创建任务列表：

- [ ] 待完成任务
- [x] 已完成任务

## 链接

使用 \`[文本](url)\` 格式添加链接：[Tiptap 官网](https://tiptap.dev)

## 表格

| 功能 | 状态 | 备注 |
|------|------|------|
| 富文本编辑 | ✅ 支持 | 完整的所见即所得编辑 |
| Markdown 快捷键 | ✅ 支持 | 输入规则自动转换 |
| 原生 Markdown | ✅ 支持 | 使用官方扩展 |
| 模式切换 | 🔄 演示 | 富文本 ↔ Markdown |

## 现成方案推荐

1. **@tiptap/extension-markdown** - 官方 Markdown 扩展 ✅ 当前使用
2. **tiptap-markdown** - 第三方 Markdown 解析器
3. **@tiptap/pm-markdown** - ProseMirror Markdown 插件包装
4. **milkdown** - 基于 ProseMirror 的 Markdown 编辑器
5. **bytemd** - 字节跳动开源的 Markdown 编辑器

## 实现建议

- **推荐方案**：使用官方 @tiptap/extension-markdown 扩展
- **简单需求**：当前方案 + 官方 Markdown 扩展
- **复杂需求**：考虑 \`milkdown\` 或 \`bytemd\`
- **自定义需求**：基于 Tiptap + markdown-it 构建

## 新增功能

- ✅ 原生 Markdown 序列化/反序列化
- ✅ 更好的 Markdown 语法支持
- ✅ 粘贴 Markdown 文本自动转换
- ✅ 复制内容为 Markdown 格式
      `,
      onUpdate: ({ editor }) => {
        // 当编辑器内容更新时，同步更新 markdown 内容
        if (!this.isMarkdownMode) {
          this.syncMarkdownFromEditor();
        }
      },
    });

    // 初始化 markdown 内容
    this.syncMarkdownFromEditor();
  },

  methods: {
    toggleMode() {
      this.isMarkdownMode = !this.isMarkdownMode;

      if (this.isMarkdownMode) {
        // 切换到 Markdown 模式
        this.syncMarkdownFromEditor();
      } else {
        // 切换到富文本模式
        this.syncEditorFromMarkdown();
      }
    },

    syncMarkdownFromEditor() {
      // 使用官方 Markdown 扩展的序列化功能
      this.markdownContent = this.editor.storage.markdown.getMarkdown();
    },

    syncEditorFromMarkdown() {
      // 使用官方 Markdown 扩展的反序列化功能
      this.editor.commands.setContent(this.markdownContent, false, { preserveWhitespace: 'full' });
    },

    updateFromMarkdown() {
      // Markdown 模式下内容更新时的处理
      if (this.isMarkdownMode) {
        // 可以添加实时预览逻辑
        // 这里暂时不做实时同步，避免性能问题
      }
    },

    getMarkdown() {
      const markdown = this.isMarkdownMode ?
        this.markdownContent :
        this.editor.storage.markdown.getMarkdown();
      this.markdownOutput = markdown;
    },

    // 保留简化版转换方法作为备用（官方扩展优先）
    htmlToMarkdown(html) {
      return html
        .replace(/<h([1-6])>(.*?)<\/h[1-6]>/g, (match, level, content) => '#'.repeat(parseInt(level)) + ' ' + content + '\n\n')
        .replace(/<p>(.*?)<\/p>/g, '$1\n\n')
        .replace(/<strong>(.*?)<\/strong>/g, '**$1**')
        .replace(/<em>(.*?)<\/em>/g, '*$1*')
        .replace(/<code>(.*?)<\/code>/g, '`$1`')
        .replace(/<blockquote>(.*?)<\/blockquote>/g, '> $1\n\n')
        .replace(/<li.*?>(.*?)<\/li>/g, '- $1\n')
        .replace(/<[^>]*>/g, '')
        .replace(/\n\n+/g, '\n\n')
        .trim();
    },

    markdownToHtml(markdown) {
      return markdown
        .replace(/^(#{1,6})\s+(.+)$/gm, (match, hashes, content) => `<h${hashes.length}>${content}</h${hashes.length}>`)
        .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
        .replace(/\*(.*?)\*/g, '<em>$1</em>')
        .replace(/`(.*?)`/g, '<code>$1</code>')
        .replace(/^>\s+(.+)$/gm, '<blockquote>$1</blockquote>')
        .replace(/^-\s+(.+)$/gm, '<li>$1</li>')
        .replace(/\n/g, '<br>')
        .replace(/(<li>.*<\/li>)/s, '<ul>$1</ul>');
    },
  },

  beforeUnmount() {
    this.editor.destroy();
  },
};
</script>

<style lang="scss">
.editor-controls {
  margin-bottom: 1rem;
  padding: 1rem;
  background-color: #f5f5f5;
  border-radius: 0.5rem;

  button {
    margin-right: 0.5rem;
    padding: 0.5rem 1rem;
    background-color: #007bff;
    color: white;
    border: none;
    border-radius: 0.25rem;
    cursor: pointer;

    &:hover {
      background-color: #0056b3;
    }
  }

  .get-markdown {
    background-color: #28a745;

    &:hover {
      background-color: #1e7e34;
    }
  }
}

.editor-wrapper {
  border: 1px solid #ddd;
  border-radius: 0.5rem;
  min-height: 400px;
}

.markdown-editor {
  width: 100%;
  min-height: 400px;
  padding: 1rem;
  border: none;
  resize: vertical;
  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
  font-size: 14px;
  line-height: 1.5;

  &:focus {
    outline: none;
    box-shadow: 0 0 0 2px #007bff25;
  }
}

.markdown-output {
  margin-top: 1rem;
  padding: 1rem;
  background-color: #f8f9fa;
  border-radius: 0.5rem;

  h4 {
    margin-top: 0;
    margin-bottom: 0.5rem;
  }

  pre {
    background-color: #e9ecef;
    padding: 1rem;
    border-radius: 0.25rem;
    overflow-x: auto;
    font-size: 0.875rem;
    max-height: 300px;
  }
}

/* Basic editor styles */
.tiptap {
  :first-child {
    margin-top: 0;
  }

  /* List styles */
  ul,
  ol {
    padding: 0 1rem;
    margin: 1.25rem 1rem 1.25rem 0.4rem;

    li p {
      margin-top: 0.25em;
      margin-bottom: 0.25em;
    }
  }

  /* Heading styles */
  h1,
  h2,
  h3,
  h4,
  h5,
  h6 {
    line-height: 1.1;
    margin-top: 2.5rem;
    text-wrap: pretty;
  }

  h1,
  h2 {
    margin-top: 3.5rem;
    margin-bottom: 1.5rem;
  }

  h1 {
    font-size: 1.4rem;
  }

  h2 {
    font-size: 1.2rem;
  }

  h3 {
    font-size: 1.1rem;
  }

  h4,
  h5,
  h6 {
    font-size: 1rem;
  }

  /* Code and preformatted text styles */
  code {
    background-color: var(--purple-light);
    border-radius: 0.4rem;
    color: var(--black);
    font-size: 0.85rem;
    padding: 0.25em 0.3em;
  }

  pre {
    background: var(--black);
    border-radius: 0.5rem;
    color: var(--white);
    font-family: "JetBrainsMono", monospace;
    margin: 1.5rem 0;
    padding: 0.75rem 1rem;

    code {
      background: none;
      color: inherit;
      font-size: 0.8rem;
      padding: 0;
    }
  }

  mark {
    background-color: #faf594;
    border-radius: 0.4rem;
    box-decoration-break: clone;
    padding: 0.1rem 0.3rem;
  }

  blockquote {
    border-left: 3px solid var(--gray-3);
    margin: 1.5rem 0;
    padding-left: 1rem;
  }

  hr {
    border: none;
    border-top: 1px solid var(--gray-2);
    margin: 2rem 0;
  }
}

/* Task list styles */
ul[data-type="taskList"] {
  list-style: none;
  padding: 0;

  p {
    margin: 0;
  }

  li {
    display: flex;

    > label {
      flex: 0 0 auto;
      margin-right: 0.5rem;
      user-select: none;
    }

    > div {
      flex: 1 1 auto;
    }

    ul li,
    ol li {
      display: list-item;
    }

    ul[data-type="taskList"] > li {
      display: flex;
    }
  }
}

/* Table styles */
table {
  border-collapse: collapse;
  margin: 0;
  overflow: hidden;
  table-layout: fixed;
  width: 100%;

  td,
  th {
    border: 2px solid var(--gray-3);
    box-sizing: border-box;
    min-width: 1em;
    padding: 3px 5px;
    position: relative;
    vertical-align: top;

    > * {
      margin-bottom: 0;
    }
  }

  th {
    background-color: var(--gray-1);
    font-weight: bold;
    text-align: left;
  }

  .selectedCell:after {
    background: var(--gray-2);
    content: "";
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    pointer-events: none;
    position: absolute;
    z-index: 2;
  }

  .column-resize-handle {
    background-color: var(--purple);
    bottom: -2px;
    position: absolute;
    right: -2px;
    pointer-events: none;
    top: 0;
    width: 4px;
  }

  p {
    margin: 0;
  }
}

.tableWrapper {
  overflow-x: auto;
}

.resize-cursor {
  cursor: ew-resize;
  cursor: col-resize;
}
</style>
